Background

In this project, I analyze the performance of the Milwaukee Bucks, a prominent National Basketball Association (NBA) team. We investigate the regular season data and identify the team performance indicators most significant to winning.


Source Data

Analysis


Imports & Libraries

# install.packages("tidyverse")
library(tidyverse)

# install.packages("rvest")
library(rvest)

# install.packages("janitor")
library(janitor)

# install.packages("plotly")
library(plotly)

Function to Read Tables

# Leverage Web Scarping to Create Data tables
readTables <- function(list) {
  tables <- c()
  for (i in list) {
      temp <- i %>%
      read_html() %>%
      html_nodes(css = "table") %>%
      html_table(fill = TRUE)
      tables <- c(tables, temp)
  }
  return(tables)
}

Save Tables

# Read Tables 
data <- readTables(list(prime, prime2, prime3, sec, sec2, sec3)) 

# Save Game Data for each Year
game_data1 <- data[[1]]
game_data2 <- data[[2]]
game_data3 <- data[[3]]

# Save Rank Data for each Year
rank_data1 <- data[[4]]
rank_data2 <- data[[5]]
rank_data3 <- data[[6]]

Technical Challenge: Because our tables are web scarped, each contain multiple syntax and format errors (unnecessary and repetitive columns and rows). As such, wrangling the tables into a unified syntax will be vital. Unfortunately, many inconsistencies make cleaning them all with a single function unrealistic.


Game Data Wrangling and Cleaning

# Game data for year 2022-2023
game_data1 <- game_data1[-5,] # drop first 5 rows
game_data1 <- game_data1[,-c(4,1)] # drop columns 1 and 4
game_data1 <- game_data1 %>% row_to_names(row_number = 1) # reset cols
game_data1 <- game_data1[-c(20,21,42,43,64,65,86,87),] # drop redundant rows
game_data1 <- game_data1[,-c(21,22,23,24,25,26,27,28,29,30)] # opponent stats
game_data1 <- game_data1[,-c(21,22,23,24,25,26,27)] # redundant columns
colnames(game_data1)[6] = "opp points"
colnames(game_data1)[4] = "Outcome"
game_data1$Date <- as.POSIXct(game_data1$Date, format="%Y")
game_data1$Year <- year(game_data1$Date) # create new year column

# Game data for year 2021-2022
game_data2 <- game_data2[-5,] 
game_data2 <- game_data2[,-c(4,1)] 
game_data2 <- game_data2 %>% row_to_names(row_number = 1) 
game_data2 <- game_data2[-c(20,21,42,43,64,65,86,87),] 
game_data2 <- game_data2[,-c(21,22,23,24,25,26,27,28,29,30)] 
game_data2 <- game_data2[,-c(21,22,23,24,25,26,27)]
colnames(game_data2)[6] = "opp points"
colnames(game_data2)[4] = "Outcome"
game_data2$Date <- as.POSIXct(game_data2$Date, format="%Y")
game_data2$Year <- year(game_data2$Date) 

# Game data for year 2020-2021
game_data3 <- game_data3[,-c(4,1)] 
game_data3 <- game_data3 %>% row_to_names(row_number = 1) 
colnames(game_data3)[6] = "opp points"
colnames(game_data3)[4] = "Outcome"
game_data3 <- game_data3[,-c(21,22,23,24,25,26,27,28,29,30)] 
game_data3 <- game_data3[-c(20,21,43,44,65,66),] 
game_data3 <- game_data3[,-c(21,22,23,24,25,26,27)] 
game_data3$Date <- as.POSIXct(game_data3$Date, format="%Y-%m-%d")
game_data3$Year <- year(game_data3$Date) 

Rank Data Wrangling and Cleaning

rank_data1 <- rank_data1[,-c(3,4,5,6,7)]
colnames(rank_data1)[2] = "Rank"
rank_data1 <- rank_data1 %>%
  mutate(ABV = c("BOS", "CLE","PHI", "MIL","DEN","MEM","NYK","PHO","GSW","TOR","SAC","NOP","BRK","CHI","LAC", "LAL","ATL","MIA","DAL","MIN","OKC","WAS","UTA","ORL","POR","IND","CHO","DET","HOU","SAS"))

rank_data2 <- rank_data2[,-c(3,4,5,6,7)]
colnames(rank_data2)[2] = "Rank"
rank_data2 <- rank_data2 %>%
  mutate(ABV = c("BOS","PHO","GSW","UTA","MEM","MIA", "MIL","DAL","PHI","DEN","MIN","BRK","TOR","ATL","CLE","CHO","LAC", "NYK", "NOP","CHI","SAS","LAL","IND","WAS","SAC","POR","DET","OKC","ORL","HOU"))

rank_data3 <- rank_data3[,-c(3,4,5,6,7)]
colnames(rank_data3)[2] = "Rank"
rank_data3 <- rank_data3 %>%
  mutate(ABV = c("UTA","LAC","MIL","PHO","PHI","BRK","DEN","LAL","DAL","ATL","POR","BOS","GSW","MEM","NYK","MIA","IND","TOR","NOP","CHI","SAS","WAS","CHO","SAC","DET","MIN","HOU","ORL","CLE","OKC"))

Our game and rank tables are now fully processed. Joining them using the left_join function will ensure that each case has the correct information from both datasets. Furthermore, combining the joined tables with the rbind function will produce a final table with a nearly 300-game sample size to investigate.


Combining Game Data and Rank Data

# Join Game and Ranks 
game_data1 <- game_data1 %>%
  left_join(rank_data1, by = c("Opp"="ABV"))
game_data2 <- game_data2 %>%
  left_join(rank_data2, by = c("Opp"="ABV"))
game_data3 <- game_data3 %>%
  left_join(rank_data3, by = c("Opp"="ABV"))

game_data3 <- game_data3[-20,] 

# Final Game Data Table 
games <- rbind(game_data3, game_data2, game_data1)
games <- games[-20,]

# Convert Chr to Numeric 
games[, c("G", "Tm","opp points","FG","FGA","FG%","3P","3PA","3P%","FT","FTA","FT%","ORB","TRB","AST","STL","BLK","TOV","PF","Rank")] <- lapply(games[, c("G", "Tm","opp points","FG","FGA","FG%","3P","3PA","3P%","FT","FTA","FT%","ORB","TRB","AST","STL","BLK","TOV","PF","Rank")], as.numeric)

# Inspecting Final Table 
head(games)
# summary(games)

With the help of fundamental functions like head and summary, we can see that the final “games” table is formatted correctly and ready for further analysis.

The three major categories explored in this project surround the most impactful elements of a game: Offense, Defense, and Shooting. We investigated each of these areas below.


Effect of Assist-Turnover Ratio on Outcomes (Offense)

game1 <- games %>%
  group_by(Outcome, Year, Rank) %>%
  summarise(TeamRank = paste(Team, "Rank -", Rank, sep = " "), AST = AST, TOV = TOV, AT = AST/TOV)

game_1 <- game1 %>%
  mutate(Outcome = ifelse(Outcome == "W", 1,0))

# Null Hypothesis: The value of the Assist-Turnover ratio has minimal impact game outcome

Off_corr <- cor(game_1$AT,game_1$Outcome, method = "pearson")  
Off_model <- wilcox.test(game1$AT ~ game1$Outcome, conf.int =T)

# Mean of Assist-Turnover ratio for Wins
off_wins <- game1 %>%
  select(Outcome, Year,Rank, AT) %>%
  filter(Outcome == "W")
offW_mean <- mean(off_wins$AT) 
  
# Mean of Assist-Turnover ratio for Losses
off_losses <- game1 %>%
  select(Outcome, Year, Rank, AT) %>%
  filter(Outcome == "L")
offL_mean <- mean(off_losses$AT)

print(Off_corr)
print(Off_model)
print(offW_mean)
print(offL_mean)

Let’s define the variables we focused on above: An Assist is a pass made to a teammate which leads directly to a score. A Turnover is when a player commits an error and allows the opposing team to gain possession of the ball.

Utilizing the Mann-Whitney U test, we explore the Assist-Turnover ratio’s impact on the game outcome above. The test shows a significant difference in means between games won and lost (P-Value : 0.0016). If we further interpret the calculated means, we see that more assists, in turn a higher ratio, significantly impact winning.


Supporting Visualization

game1_filtered <- filter(game1, Year != 2020)

p <- ggplot(game1_filtered, aes(x = AST, y = TOV, color = Outcome, text = TeamRank)) +
  geom_point() +
  labs(x = "Assists", y = "Turnovers", color = "Game Outcome") +
  theme_minimal() +
  facet_wrap(. ~ Year) +
  ggtitle("Assists vs. Turnovers by Game Outcome and Year") +
  theme(panel.spacing.x = unit(5, "mm"))

ggplotly(p, tooltip = c("text"), width = 900, height = 300)

The spread of the points indicates that there is little correlation. This result is consistent with the correlation we found earlier (0.144). However, despite a lack of correlation, we can observe that most games with a high Assist-Turnover ratio are wins. As such, The Buck’s coaching staff should emphasize smart and controlled ball movement to minimize turnovers and maximize assists.


Effect of Defensive Possessions on Outcomes (Defense)

game2 <- games %>%
  group_by(Outcome, Year, Rank) %>%
  summarise(TeamRank = paste(Team, "Rank -", Rank, sep = " "), PF = PF,  DRB = TRB - ORB, DES = (DRB + BLK + STL - PF), Def_ratio = PF/ DES)

game_2 <- game2 %>%
  mutate(Outcome = ifelse(Outcome == "W", 1,0))

# Null Hypothesis: The value of the Defensive ratio has minimal impact game outcome

def_corr <- cor(game_2$Def_ratio,game_2$Outcome, method = "pearson")  
def_model <- wilcox.test(game2$Def_ratio ~ game2$Outcome, conf.int =T)

# Mean of Defensive ratio for Wins
def_wins <- game2 %>%
  select(Outcome, Year, Rank, Def_ratio) %>%
  filter(Outcome == "W")
defW_mean <- mean(def_wins$Def_ratio) 
  
# Mean of Defensive ratio for Losses
def_losses <- game2 %>%
  select(Outcome, Year, Rank, Def_ratio) %>%
  filter(Outcome == "L")
defL_mean <- mean(def_losses$Def_ratio)

print(def_corr) # Correlation
print(def_model) # U Test
print(defW_mean) # Mean of Defensive ratio for Wins
print(defL_mean) # Mean of Defensive ratio for Losses

Let’s define the variables we focused on here: A Personal Foul (PF) is any illegal contact with an offensive player, including pushing and striking. The Defensive Efficiency Score (DES) is the difference between good and bad defensive actions.

Now we explored Defensive Possession’s impact on the game outcome above. The Mann-Whitney U tests show a significant difference in means between games won and lost (P-Value : 0.0003). If we further interpret the calculated means, we see that fewer personal fouls significantly impact winning.


Supporting Visualization

game2_filtered <- filter(game2, Year != 2020)

p2 <- ggplot(game2_filtered, aes(x = DES, y = PF , color = Outcome, text =TeamRank)) +
  geom_point() +
  labs(x = "Defensive Efficiency Score", y = "Personal Fouls Commited", color = "Game Outcome") +
  theme_minimal() +
  facet_wrap(. ~ Year) +
  ggtitle("Efficiency of Defensive Possessions") +
  theme(panel.spacing.x = unit(5, "mm"))

ggplotly(p2, tooltip = c("text"), width = 900, height = 300)
NA

In the graphs above, we can see a moderate negative correlation between our variables. This result is consistent with the correlation we found earlier (-0.277). This relationship suggests that personal fouls decrease as DES increases. Combining correlation and difference of means we can advise the Buck’s coaching staff to emphasize strategic positioning and team defense to win the most games.


Effect of Thee Point Field Goal Attempts on Outcomes (Shooting)

game3 <- games %>%
  group_by(Outcome, Year, Rank) %>%
  summarise(TeamRank = paste(Team, "Rank -", Rank, sep = " "), `3PA` = `3PA`, `3P%` = `3P%`, Percent_attempt = (`3P%`/`3PA`))

game_3 <- game3 %>%
  mutate(Outcome = ifelse(Outcome == "W", 1,0))

# Null Hypothesis: The value of the Percent-Attempt ratio has minimal impact game outcome

shot_corr <- cor(game_3$Percent_attempt,game_3$`3PA`, method = "pearson")  
shot_model <- wilcox.test(game3$Percent_attempt ~ game3$Outcome, conf.int =T)

# Mean of Percent-Attempt ratio for Wins
shot_wins <- game3 %>%
  select(Outcome, Year, Rank, Percent_attempt) %>%
  filter(Outcome == "W")
shotW_mean <- mean(shot_wins$Percent_attempt) 
  
# Mean of Percent-Attempt ratio for Losses
shot_losses <- game3 %>%
  select(Outcome, Year, Rank, Percent_attempt) %>%
  filter(Outcome == "L")
shotL_mean <- mean(shot_losses$Percent_attempt)

print(shot_corr) # Correlation
print(shot_model) # U Test
print(shotW_mean) # Mean of Percent-Attempt ratio for Wins
print(shotL_mean) # Mean of Percent-Attempt ratio for Losses

Let’s define the variables we focused on above: A three-point attempt is a shot released from any position behind the three-point arc. The percent-attempt ratio takes both shooting accuracy and the volume into account to measure shooting efficency.

Here, we explored the percent-attempt ratio’s impact on the game outcome above. The Mann-Whitney U tests, once again, show a significant difference in means between games won and lost (P-Value : 0.0003). If we further interpret the calculated means, we see that fewer personal fouls significantly impact winning.


Supporting Visualization

game3_filtered <- filter(game3, Year != 2020)

p3 <- ggplot(game3_filtered, aes(x = Percent_attempt, y = `3PA` , color = Outcome, text =TeamRank)) +
  geom_point()+
  labs(x = "Shooting Accuracy Score", y = "3 Point Field Goal Attempts", color = "Game Outcome") +
  theme_minimal() +
  facet_wrap(. ~ Year) +
  ggtitle("Impact of 3 Point Field Goal Attempts") +
  theme(panel.spacing.x = unit(5, "mm"))

ggplotly(p3, tooltip = c("text"), width = 900, height = 300)

Finally, we can see the strongest negative correlation between our variables (-0.592). This relationship suggests that as three-point attempts decrease, the percent-attempt ratio increases. Combining correlation and the U test we can advise Buck’s coaching staff to strategize and create open shoots instead of frequent ones.


Conclusion

After examining the three most impactful elements (Offense, Defense, and Shooting), we provided the Milwaukee Bucks coaching staff with meaningful insights backed by reliable statistical tests. Now, it is up to their organization to implement them appropriately as they enter the playoffs.


LS0tDQp0aXRsZTogIk1pbHdhdWtlZSBCdWNrcyBBbmFseXNpcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoqKioqKg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCiMjIyBfX0JhY2tncm91bmRfXw0KDQojIyMgSW4gdGhpcyBwcm9qZWN0LCBJIGFuYWx5emUgdGhlIHBlcmZvcm1hbmNlIG9mIHRoZSBNaWx3YXVrZWUgQnVja3MsIGEgcHJvbWluZW50IE5hdGlvbmFsIEJhc2tldGJhbGwgQXNzb2NpYXRpb24gKE5CQSkgdGVhbS4gV2UgaW52ZXN0aWdhdGUgdGhlIHJlZ3VsYXIgc2Vhc29uIGRhdGEgYW5kIGlkZW50aWZ5IHRoZSB0ZWFtIHBlcmZvcm1hbmNlIGluZGljYXRvcnMgbW9zdCBzaWduaWZpY2FudCB0byB3aW5uaW5nLiANCioqKioqDQoNCiMjIyBfX1NvdXJjZSBEYXRhX18NCg0KIyMjIyBbUHJpbWFyeSBEYXRhXShodHRwczovL3d3dy5iYXNrZXRiYWxsLXJlZmVyZW5jZS5jb20vdGVhbXMvTUlMLzIwMjMvZ2FtZWxvZy8pDQoNCiMjIyMgW1NlY29uZGFyeSBEYXRhXShodHRwczovL3d3dy50ZWFtcmFua2luZ3MuY29tL25iYS9yYW5raW5ncy90ZWFtcy8/ZGF0YT0yMDIzLTA0LTIyKQ0KDQojIyMjIFtBZGRpdGlvbmFsIEluZm9ybWF0aW9uXShodHRwczovL2dpdGh1Yi5jb20vTW9oYW1lZC1FbG16L01pbHdhdWtlZS1CdWNrcy1BbmFseXNpcykNCg0KKioqKioNCiMjIyBfX0FuYWx5c2lzX18NCioqKioqDQojIyMjIEltcG9ydHMgJiBMaWJyYXJpZXMNCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCiMgaW5zdGFsbC5wYWNrYWdlcygicnZlc3QiKQ0KbGlicmFyeShydmVzdCkNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJqYW5pdG9yIikNCmxpYnJhcnkoamFuaXRvcikNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KbGlicmFyeShwbG90bHkpDQpgYGANCiMjIyMgV2VicGFnZSBMaW5rcw0KYGBge3J9DQojIFByaW1hcnkgRGF0YSBTb3VyY2UgZnJvbSAyMDIwLTIwMjMNCnByaW1lIDwtICJodHRwczovL3d3dy5iYXNrZXRiYWxsLXJlZmVyZW5jZS5jb20vdGVhbXMvTUlMLzIwMjMvZ2FtZWxvZy8iDQpwcmltZTIgPC0gImh0dHBzOi8vd3d3LmJhc2tldGJhbGwtcmVmZXJlbmNlLmNvbS90ZWFtcy9NSUwvMjAyMi9nYW1lbG9nLyINCnByaW1lMyA8LSAiaHR0cHM6Ly93d3cuYmFza2V0YmFsbC1yZWZlcmVuY2UuY29tL3RlYW1zL01JTC8yMDIxL2dhbWVsb2cvIg0KDQojIFNlY29uZGFyeSBEYXRhIFNvdXJjZSBmcm9tIDIwMjAtMjAyMw0Kc2VjIDwtICJodHRwczovL3d3dy50ZWFtcmFua2luZ3MuY29tL25iYS9yYW5raW5ncy90ZWFtcy8/ZGF0ZT0yMDIzLTA0LTIyIg0Kc2VjMiA8LSAiaHR0cHM6Ly93d3cudGVhbXJhbmtpbmdzLmNvbS9uYmEvcmFua2luZ3MvdGVhbXMvP2RhdGU9MjAyMi0wNi0xNyINCnNlYzMgPC0gImh0dHBzOi8vd3d3LnRlYW1yYW5raW5ncy5jb20vbmJhL3JhbmtpbmdzL3RlYW1zLz9kYXRlPTIwMjEtMDctMjEiDQpgYGANCiMjIyMgRnVuY3Rpb24gdG8gUmVhZCBUYWJsZXMgDQpgYGB7cn0NCiMgTGV2ZXJhZ2UgV2ViIFNjYXJwaW5nIHRvIENyZWF0ZSBEYXRhIHRhYmxlcw0KcmVhZFRhYmxlcyA8LSBmdW5jdGlvbihsaXN0KSB7DQogIHRhYmxlcyA8LSBjKCkNCiAgZm9yIChpIGluIGxpc3QpIHsNCiAgICAgIHRlbXAgPC0gaSAlPiUNCiAgICAgIHJlYWRfaHRtbCgpICU+JQ0KICAgICAgaHRtbF9ub2Rlcyhjc3MgPSAidGFibGUiKSAlPiUNCiAgICAgIGh0bWxfdGFibGUoZmlsbCA9IFRSVUUpDQogICAgICB0YWJsZXMgPC0gYyh0YWJsZXMsIHRlbXApDQogIH0NCiAgcmV0dXJuKHRhYmxlcykNCn0NCmBgYA0KIyMjIyBTYXZlIFRhYmxlcw0KYGBge3J9DQojIFJlYWQgVGFibGVzIA0KZGF0YSA8LSByZWFkVGFibGVzKGxpc3QocHJpbWUsIHByaW1lMiwgcHJpbWUzLCBzZWMsIHNlYzIsIHNlYzMpKSANCg0KIyBTYXZlIEdhbWUgRGF0YSBmb3IgZWFjaCBZZWFyDQpnYW1lX2RhdGExIDwtIGRhdGFbWzFdXQ0KZ2FtZV9kYXRhMiA8LSBkYXRhW1syXV0NCmdhbWVfZGF0YTMgPC0gZGF0YVtbM11dDQoNCiMgU2F2ZSBSYW5rIERhdGEgZm9yIGVhY2ggWWVhcg0KcmFua19kYXRhMSA8LSBkYXRhW1s0XV0NCnJhbmtfZGF0YTIgPC0gZGF0YVtbNV1dDQpyYW5rX2RhdGEzIDwtIGRhdGFbWzZdXQ0KYGBgDQoqKioqKg0KIyMjIyBfX1RlY2huaWNhbCBDaGFsbGVuZ2U6X18gQmVjYXVzZSBvdXIgdGFibGVzIGFyZSB3ZWIgc2NhcnBlZCwgZWFjaCBjb250YWluIG11bHRpcGxlIHN5bnRheCBhbmQgZm9ybWF0IGVycm9ycyAodW5uZWNlc3NhcnkgYW5kIHJlcGV0aXRpdmUgY29sdW1ucyBhbmQgcm93cykuIEFzIHN1Y2gsIHdyYW5nbGluZyB0aGUgdGFibGVzIGludG8gYSB1bmlmaWVkIHN5bnRheCB3aWxsIGJlIHZpdGFsLiBVbmZvcnR1bmF0ZWx5LCBtYW55IGluY29uc2lzdGVuY2llcyBtYWtlIGNsZWFuaW5nIHRoZW0gYWxsIHdpdGggYSBzaW5nbGUgZnVuY3Rpb24gdW5yZWFsaXN0aWMuIA0KKioqKioNCiMjIyMgR2FtZSBEYXRhIFdyYW5nbGluZyBhbmQgQ2xlYW5pbmcNCmBgYHtyfQ0KIyBHYW1lIGRhdGEgZm9yIHllYXIgMjAyMi0yMDIzDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTFbLTUsXSAjIGRyb3AgZmlyc3QgNSByb3dzDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTFbLC1jKDQsMSldICMgZHJvcCBjb2x1bW5zIDEgYW5kIDQNCmdhbWVfZGF0YTEgPC0gZ2FtZV9kYXRhMSAlPiUgcm93X3RvX25hbWVzKHJvd19udW1iZXIgPSAxKSAjIHJlc2V0IGNvbHMNCmdhbWVfZGF0YTEgPC0gZ2FtZV9kYXRhMVstYygyMCwyMSw0Miw0Myw2NCw2NSw4Niw4NyksXSAjIGRyb3AgcmVkdW5kYW50IHJvd3MNCmdhbWVfZGF0YTEgPC0gZ2FtZV9kYXRhMVssLWMoMjEsMjIsMjMsMjQsMjUsMjYsMjcsMjgsMjksMzApXSAjIG9wcG9uZW50IHN0YXRzDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTFbLC1jKDIxLDIyLDIzLDI0LDI1LDI2LDI3KV0gIyByZWR1bmRhbnQgY29sdW1ucw0KY29sbmFtZXMoZ2FtZV9kYXRhMSlbNl0gPSAib3BwIHBvaW50cyINCmNvbG5hbWVzKGdhbWVfZGF0YTEpWzRdID0gIk91dGNvbWUiDQpnYW1lX2RhdGExJERhdGUgPC0gYXMuUE9TSVhjdChnYW1lX2RhdGExJERhdGUsIGZvcm1hdD0iJVkiKQ0KZ2FtZV9kYXRhMSRZZWFyIDwtIHllYXIoZ2FtZV9kYXRhMSREYXRlKSAjIGNyZWF0ZSBuZXcgeWVhciBjb2x1bW4NCg0KIyBHYW1lIGRhdGEgZm9yIHllYXIgMjAyMS0yMDIyDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLTUsXSANCmdhbWVfZGF0YTIgPC0gZ2FtZV9kYXRhMlssLWMoNCwxKV0gDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTIgJT4lIHJvd190b19uYW1lcyhyb3dfbnVtYmVyID0gMSkgDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLWMoMjAsMjEsNDIsNDMsNjQsNjUsODYsODcpLF0gDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLC1jKDIxLDIyLDIzLDI0LDI1LDI2LDI3LDI4LDI5LDMwKV0gDQpnYW1lX2RhdGEyIDwtIGdhbWVfZGF0YTJbLC1jKDIxLDIyLDIzLDI0LDI1LDI2LDI3KV0NCmNvbG5hbWVzKGdhbWVfZGF0YTIpWzZdID0gIm9wcCBwb2ludHMiDQpjb2xuYW1lcyhnYW1lX2RhdGEyKVs0XSA9ICJPdXRjb21lIg0KZ2FtZV9kYXRhMiREYXRlIDwtIGFzLlBPU0lYY3QoZ2FtZV9kYXRhMiREYXRlLCBmb3JtYXQ9IiVZIikNCmdhbWVfZGF0YTIkWWVhciA8LSB5ZWFyKGdhbWVfZGF0YTIkRGF0ZSkgDQoNCiMgR2FtZSBkYXRhIGZvciB5ZWFyIDIwMjAtMjAyMQ0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWywtYyg0LDEpXSANCmdhbWVfZGF0YTMgPC0gZ2FtZV9kYXRhMyAlPiUgcm93X3RvX25hbWVzKHJvd19udW1iZXIgPSAxKSANCmNvbG5hbWVzKGdhbWVfZGF0YTMpWzZdID0gIm9wcCBwb2ludHMiDQpjb2xuYW1lcyhnYW1lX2RhdGEzKVs0XSA9ICJPdXRjb21lIg0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWywtYygyMSwyMiwyMywyNCwyNSwyNiwyNywyOCwyOSwzMCldIA0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWy1jKDIwLDIxLDQzLDQ0LDY1LDY2KSxdIA0KZ2FtZV9kYXRhMyA8LSBnYW1lX2RhdGEzWywtYygyMSwyMiwyMywyNCwyNSwyNiwyNyldIA0KZ2FtZV9kYXRhMyREYXRlIDwtIGFzLlBPU0lYY3QoZ2FtZV9kYXRhMyREYXRlLCBmb3JtYXQ9IiVZLSVtLSVkIikNCmdhbWVfZGF0YTMkWWVhciA8LSB5ZWFyKGdhbWVfZGF0YTMkRGF0ZSkgDQpgYGANCiMjIyMgUmFuayBEYXRhIFdyYW5nbGluZyBhbmQgQ2xlYW5pbmcgDQpgYGB7cn0NCnJhbmtfZGF0YTEgPC0gcmFua19kYXRhMVssLWMoMyw0LDUsNiw3KV0NCmNvbG5hbWVzKHJhbmtfZGF0YTEpWzJdID0gIlJhbmsiDQpyYW5rX2RhdGExIDwtIHJhbmtfZGF0YTEgJT4lDQogIG11dGF0ZShBQlYgPSBjKCJCT1MiLCAiQ0xFIiwiUEhJIiwgIk1JTCIsIkRFTiIsIk1FTSIsIk5ZSyIsIlBITyIsIkdTVyIsIlRPUiIsIlNBQyIsIk5PUCIsIkJSSyIsIkNISSIsIkxBQyIsICJMQUwiLCJBVEwiLCJNSUEiLCJEQUwiLCJNSU4iLCJPS0MiLCJXQVMiLCJVVEEiLCJPUkwiLCJQT1IiLCJJTkQiLCJDSE8iLCJERVQiLCJIT1UiLCJTQVMiKSkNCg0KcmFua19kYXRhMiA8LSByYW5rX2RhdGEyWywtYygzLDQsNSw2LDcpXQ0KY29sbmFtZXMocmFua19kYXRhMilbMl0gPSAiUmFuayINCnJhbmtfZGF0YTIgPC0gcmFua19kYXRhMiAlPiUNCiAgbXV0YXRlKEFCViA9IGMoIkJPUyIsIlBITyIsIkdTVyIsIlVUQSIsIk1FTSIsIk1JQSIsICJNSUwiLCJEQUwiLCJQSEkiLCJERU4iLCJNSU4iLCJCUksiLCJUT1IiLCJBVEwiLCJDTEUiLCJDSE8iLCJMQUMiLCAiTllLIiwgIk5PUCIsIkNISSIsIlNBUyIsIkxBTCIsIklORCIsIldBUyIsIlNBQyIsIlBPUiIsIkRFVCIsIk9LQyIsIk9STCIsIkhPVSIpKQ0KDQpyYW5rX2RhdGEzIDwtIHJhbmtfZGF0YTNbLC1jKDMsNCw1LDYsNyldDQpjb2xuYW1lcyhyYW5rX2RhdGEzKVsyXSA9ICJSYW5rIg0KcmFua19kYXRhMyA8LSByYW5rX2RhdGEzICU+JQ0KICBtdXRhdGUoQUJWID0gYygiVVRBIiwiTEFDIiwiTUlMIiwiUEhPIiwiUEhJIiwiQlJLIiwiREVOIiwiTEFMIiwiREFMIiwiQVRMIiwiUE9SIiwiQk9TIiwiR1NXIiwiTUVNIiwiTllLIiwiTUlBIiwiSU5EIiwiVE9SIiwiTk9QIiwiQ0hJIiwiU0FTIiwiV0FTIiwiQ0hPIiwiU0FDIiwiREVUIiwiTUlOIiwiSE9VIiwiT1JMIiwiQ0xFIiwiT0tDIikpDQpgYGANCioqKioqDQojIyMjIE91ciBnYW1lIGFuZCByYW5rIHRhYmxlcyBhcmUgbm93IGZ1bGx5IHByb2Nlc3NlZC4gSm9pbmluZyB0aGVtIHVzaW5nIHRoZSBsZWZ0X2pvaW4gZnVuY3Rpb24gd2lsbCBlbnN1cmUgdGhhdCBlYWNoIGNhc2UgaGFzIHRoZSBjb3JyZWN0IGluZm9ybWF0aW9uIGZyb20gYm90aCBkYXRhc2V0cy4gRnVydGhlcm1vcmUsIGNvbWJpbmluZyB0aGUgam9pbmVkIHRhYmxlcyB3aXRoIHRoZSByYmluZCBmdW5jdGlvbiB3aWxsIHByb2R1Y2UgYSBmaW5hbCB0YWJsZSB3aXRoIGEgbmVhcmx5IDMwMC1nYW1lIHNhbXBsZSBzaXplIHRvIGludmVzdGlnYXRlLg0KDQoqKioqKg0KDQojIyMjIENvbWJpbmluZyBHYW1lIERhdGEgYW5kIFJhbmsgRGF0YQ0KYGBge3J9DQojIEpvaW4gR2FtZSBhbmQgUmFua3MgDQpnYW1lX2RhdGExIDwtIGdhbWVfZGF0YTEgJT4lDQogIGxlZnRfam9pbihyYW5rX2RhdGExLCBieSA9IGMoIk9wcCI9IkFCViIpKQ0KZ2FtZV9kYXRhMiA8LSBnYW1lX2RhdGEyICU+JQ0KICBsZWZ0X2pvaW4ocmFua19kYXRhMiwgYnkgPSBjKCJPcHAiPSJBQlYiKSkNCmdhbWVfZGF0YTMgPC0gZ2FtZV9kYXRhMyAlPiUNCiAgbGVmdF9qb2luKHJhbmtfZGF0YTMsIGJ5ID0gYygiT3BwIj0iQUJWIikpDQoNCmdhbWVfZGF0YTMgPC0gZ2FtZV9kYXRhM1stMjAsXSANCg0KIyBGaW5hbCBHYW1lIERhdGEgVGFibGUgDQpnYW1lcyA8LSByYmluZChnYW1lX2RhdGEzLCBnYW1lX2RhdGEyLCBnYW1lX2RhdGExKQ0KZ2FtZXMgPC0gZ2FtZXNbLTIwLF0NCg0KIyBDb252ZXJ0IENociB0byBOdW1lcmljIA0KZ2FtZXNbLCBjKCJHIiwgIlRtIiwib3BwIHBvaW50cyIsIkZHIiwiRkdBIiwiRkclIiwiM1AiLCIzUEEiLCIzUCUiLCJGVCIsIkZUQSIsIkZUJSIsIk9SQiIsIlRSQiIsIkFTVCIsIlNUTCIsIkJMSyIsIlRPViIsIlBGIiwiUmFuayIpXSA8LSBsYXBwbHkoZ2FtZXNbLCBjKCJHIiwgIlRtIiwib3BwIHBvaW50cyIsIkZHIiwiRkdBIiwiRkclIiwiM1AiLCIzUEEiLCIzUCUiLCJGVCIsIkZUQSIsIkZUJSIsIk9SQiIsIlRSQiIsIkFTVCIsIlNUTCIsIkJMSyIsIlRPViIsIlBGIiwiUmFuayIpXSwgYXMubnVtZXJpYykNCg0KIyBJbnNwZWN0aW5nIEZpbmFsIFRhYmxlIA0KaGVhZChnYW1lcykNCiMgc3VtbWFyeShnYW1lcykNCmBgYA0KKioqKioNCiMjIyMgV2l0aCB0aGUgaGVscCBvZiBmdW5kYW1lbnRhbCBmdW5jdGlvbnMgbGlrZSBoZWFkIGFuZCBzdW1tYXJ5LCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGZpbmFsICJnYW1lcyIgdGFibGUgaXMgZm9ybWF0dGVkIGNvcnJlY3RseSBhbmQgcmVhZHkgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuDQoNCiMjIyMgVGhlIHRocmVlIG1ham9yIGNhdGVnb3JpZXMgZXhwbG9yZWQgaW4gdGhpcyBwcm9qZWN0IHN1cnJvdW5kIHRoZSBtb3N0IGltcGFjdGZ1bCBlbGVtZW50cyBvZiBhIGdhbWU6IE9mZmVuc2UsIERlZmVuc2UsIGFuZCBTaG9vdGluZy4gV2UgaW52ZXN0aWdhdGVkIGVhY2ggb2YgdGhlc2UgYXJlYXMgYmVsb3cuDQoqKioqKg0KDQojIyMjIEVmZmVjdCBvZiBBc3Npc3QtVHVybm92ZXIgUmF0aW8gb24gT3V0Y29tZXMgKE9mZmVuc2UpDQpgYGB7cn0NCmdhbWUxIDwtIGdhbWVzICU+JQ0KICBncm91cF9ieShPdXRjb21lLCBZZWFyLCBSYW5rKSAlPiUNCiAgc3VtbWFyaXNlKFRlYW1SYW5rID0gcGFzdGUoVGVhbSwgIlJhbmsgLSIsIFJhbmssIHNlcCA9ICIgIiksIEFTVCA9IEFTVCwgVE9WID0gVE9WLCBBVCA9IEFTVC9UT1YpDQoNCmdhbWVfMSA8LSBnYW1lMSAlPiUNCiAgbXV0YXRlKE91dGNvbWUgPSBpZmVsc2UoT3V0Y29tZSA9PSAiVyIsIDEsMCkpDQoNCiMgTnVsbCBIeXBvdGhlc2lzOiBUaGUgdmFsdWUgb2YgdGhlIEFzc2lzdC1UdXJub3ZlciByYXRpbyBoYXMgbWluaW1hbCBpbXBhY3QgZ2FtZSBvdXRjb21lDQoNCk9mZl9jb3JyIDwtIGNvcihnYW1lXzEkQVQsZ2FtZV8xJE91dGNvbWUsIG1ldGhvZCA9ICJwZWFyc29uIikgIA0KT2ZmX21vZGVsIDwtIHdpbGNveC50ZXN0KGdhbWUxJEFUIH4gZ2FtZTEkT3V0Y29tZSwgY29uZi5pbnQgPVQpDQoNCiMgTWVhbiBvZiBBc3Npc3QtVHVybm92ZXIgcmF0aW8gZm9yIFdpbnMNCm9mZl93aW5zIDwtIGdhbWUxICU+JQ0KICBzZWxlY3QoT3V0Y29tZSwgWWVhcixSYW5rLCBBVCkgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJXIikNCm9mZldfbWVhbiA8LSBtZWFuKG9mZl93aW5zJEFUKSANCiAgDQojIE1lYW4gb2YgQXNzaXN0LVR1cm5vdmVyIHJhdGlvIGZvciBMb3NzZXMNCm9mZl9sb3NzZXMgPC0gZ2FtZTEgJT4lDQogIHNlbGVjdChPdXRjb21lLCBZZWFyLCBSYW5rLCBBVCkgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJMIikNCm9mZkxfbWVhbiA8LSBtZWFuKG9mZl9sb3NzZXMkQVQpDQoNCnByaW50KE9mZl9jb3JyKQ0KcHJpbnQoT2ZmX21vZGVsKQ0KcHJpbnQob2ZmV19tZWFuKQ0KcHJpbnQob2ZmTF9tZWFuKQ0KYGBgDQoqKioqKg0KIyMjIyBMZXQncyBkZWZpbmUgdGhlIHZhcmlhYmxlcyB3ZSBmb2N1c2VkIG9uIGFib3ZlOiBBbiBBc3Npc3QgaXMgYSBwYXNzIG1hZGUgdG8gYSB0ZWFtbWF0ZSB3aGljaCBsZWFkcyBkaXJlY3RseSB0byBhIHNjb3JlLiBBIFR1cm5vdmVyIGlzIHdoZW4gYSBwbGF5ZXIgY29tbWl0cyBhbiBlcnJvciBhbmQgYWxsb3dzIHRoZSBvcHBvc2luZyB0ZWFtIHRvIGdhaW4gcG9zc2Vzc2lvbiBvZiB0aGUgYmFsbC4gDQoNCiMjIyMgVXRpbGl6aW5nIHRoZSBNYW5uLVdoaXRuZXkgVSB0ZXN0LCB3ZSBleHBsb3JlIHRoZSBBc3Npc3QtVHVybm92ZXIgcmF0aW8ncyBpbXBhY3Qgb24gdGhlIGdhbWUgb3V0Y29tZSBhYm92ZS4gVGhlIHRlc3Qgc2hvd3MgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIG1lYW5zIGJldHdlZW4gZ2FtZXMgd29uIGFuZCBsb3N0IChQLVZhbHVlIDogMC4wMDE2KS4gSWYgd2UgZnVydGhlciBpbnRlcnByZXQgdGhlIGNhbGN1bGF0ZWQgbWVhbnMsIHdlIHNlZSB0aGF0IG1vcmUgYXNzaXN0cywgaW4gdHVybiBhIGhpZ2hlciByYXRpbywgc2lnbmlmaWNhbnRseSBpbXBhY3Qgd2lubmluZy4NCg0KKioqKioNCiMjIyMgU3VwcG9ydGluZyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCmdhbWUxX2ZpbHRlcmVkIDwtIGZpbHRlcihnYW1lMSwgWWVhciAhPSAyMDIwKQ0KDQpwIDwtIGdncGxvdChnYW1lMV9maWx0ZXJlZCwgYWVzKHggPSBBU1QsIHkgPSBUT1YsIGNvbG9yID0gT3V0Y29tZSwgdGV4dCA9IFRlYW1SYW5rKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHggPSAiQXNzaXN0cyIsIHkgPSAiVHVybm92ZXJzIiwgY29sb3IgPSAiR2FtZSBPdXRjb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKC4gfiBZZWFyKSArDQogIGdndGl0bGUoIkFzc2lzdHMgdnMuIFR1cm5vdmVycyBieSBHYW1lIE91dGNvbWUgYW5kIFllYXIiKSArDQogIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoNSwgIm1tIikpDQoNCmdncGxvdGx5KHAsIHRvb2x0aXAgPSBjKCJ0ZXh0IiksIHdpZHRoID0gOTAwLCBoZWlnaHQgPSAzMDApDQpgYGANCg0KKioqKioNCiMjIyMgVGhlIHNwcmVhZCBvZiB0aGUgcG9pbnRzIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIGxpdHRsZSBjb3JyZWxhdGlvbi4gVGhpcyByZXN1bHQgaXMgY29uc2lzdGVudCB3aXRoIHRoZSBjb3JyZWxhdGlvbiB3ZSBmb3VuZCBlYXJsaWVyICgwLjE0NCkuIEhvd2V2ZXIsIGRlc3BpdGUgYSBsYWNrIG9mIGNvcnJlbGF0aW9uLCB3ZSBjYW4gb2JzZXJ2ZSB0aGF0IG1vc3QgZ2FtZXMgd2l0aCBhIGhpZ2ggQXNzaXN0LVR1cm5vdmVyIHJhdGlvIGFyZSB3aW5zLiBBcyBzdWNoLCBUaGUgQnVjaydzIGNvYWNoaW5nIHN0YWZmIHNob3VsZCBlbXBoYXNpemUgc21hcnQgYW5kIGNvbnRyb2xsZWQgYmFsbCBtb3ZlbWVudCB0byBtaW5pbWl6ZSB0dXJub3ZlcnMgYW5kIG1heGltaXplIGFzc2lzdHMuDQoNCioqKioqDQojIyMjIEVmZmVjdCBvZiBEZWZlbnNpdmUgUG9zc2Vzc2lvbnMgb24gT3V0Y29tZXMgKERlZmVuc2UpDQpgYGB7cn0NCmdhbWUyIDwtIGdhbWVzICU+JQ0KICBncm91cF9ieShPdXRjb21lLCBZZWFyLCBSYW5rKSAlPiUNCiAgc3VtbWFyaXNlKFRlYW1SYW5rID0gcGFzdGUoVGVhbSwgIlJhbmsgLSIsIFJhbmssIHNlcCA9ICIgIiksIFBGID0gUEYsICBEUkIgPSBUUkIgLSBPUkIsIERFUyA9IChEUkIgKyBCTEsgKyBTVEwgLSBQRiksIERlZl9yYXRpbyA9IFBGLyBERVMpDQoNCmdhbWVfMiA8LSBnYW1lMiAlPiUNCiAgbXV0YXRlKE91dGNvbWUgPSBpZmVsc2UoT3V0Y29tZSA9PSAiVyIsIDEsMCkpDQoNCiMgTnVsbCBIeXBvdGhlc2lzOiBUaGUgdmFsdWUgb2YgdGhlIERlZmVuc2l2ZSByYXRpbyBoYXMgbWluaW1hbCBpbXBhY3QgZ2FtZSBvdXRjb21lDQoNCmRlZl9jb3JyIDwtIGNvcihnYW1lXzIkRGVmX3JhdGlvLGdhbWVfMiRPdXRjb21lLCBtZXRob2QgPSAicGVhcnNvbiIpICANCmRlZl9tb2RlbCA8LSB3aWxjb3gudGVzdChnYW1lMiREZWZfcmF0aW8gfiBnYW1lMiRPdXRjb21lLCBjb25mLmludCA9VCkNCg0KIyBNZWFuIG9mIERlZmVuc2l2ZSByYXRpbyBmb3IgV2lucw0KZGVmX3dpbnMgPC0gZ2FtZTIgJT4lDQogIHNlbGVjdChPdXRjb21lLCBZZWFyLCBSYW5rLCBEZWZfcmF0aW8pICU+JQ0KICBmaWx0ZXIoT3V0Y29tZSA9PSAiVyIpDQpkZWZXX21lYW4gPC0gbWVhbihkZWZfd2lucyREZWZfcmF0aW8pIA0KICANCiMgTWVhbiBvZiBEZWZlbnNpdmUgcmF0aW8gZm9yIExvc3Nlcw0KZGVmX2xvc3NlcyA8LSBnYW1lMiAlPiUNCiAgc2VsZWN0KE91dGNvbWUsIFllYXIsIFJhbmssIERlZl9yYXRpbykgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJMIikNCmRlZkxfbWVhbiA8LSBtZWFuKGRlZl9sb3NzZXMkRGVmX3JhdGlvKQ0KDQpwcmludChkZWZfY29ycikgIyBDb3JyZWxhdGlvbg0KcHJpbnQoZGVmX21vZGVsKSAjIFUgVGVzdA0KcHJpbnQoZGVmV19tZWFuKSAjIE1lYW4gb2YgRGVmZW5zaXZlIHJhdGlvIGZvciBXaW5zDQpwcmludChkZWZMX21lYW4pICMgTWVhbiBvZiBEZWZlbnNpdmUgcmF0aW8gZm9yIExvc3Nlcw0KDQpgYGANCioqKioqDQojIyMjIExldCdzIGRlZmluZSB0aGUgdmFyaWFibGVzIHdlIGZvY3VzZWQgb24gaGVyZTogQSBQZXJzb25hbCBGb3VsIChQRikgaXMgYW55IGlsbGVnYWwgY29udGFjdCB3aXRoIGFuIG9mZmVuc2l2ZSBwbGF5ZXIsIGluY2x1ZGluZyBwdXNoaW5nIGFuZCBzdHJpa2luZy4gVGhlIERlZmVuc2l2ZSBFZmZpY2llbmN5IFNjb3JlIChERVMpIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gZ29vZCBhbmQgYmFkIGRlZmVuc2l2ZSBhY3Rpb25zLg0KDQojIyMjIE5vdyB3ZSBleHBsb3JlZCBEZWZlbnNpdmUgUG9zc2Vzc2lvbidzIGltcGFjdCBvbiB0aGUgZ2FtZSBvdXRjb21lIGFib3ZlLiBUaGUgTWFubi1XaGl0bmV5IFUgdGVzdHMgc2hvdyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gbWVhbnMgYmV0d2VlbiBnYW1lcyB3b24gYW5kIGxvc3QgKFAtVmFsdWUgOiAwLjAwMDMpLiBJZiB3ZSBmdXJ0aGVyIGludGVycHJldCB0aGUgY2FsY3VsYXRlZCBtZWFucywgd2Ugc2VlIHRoYXQgZmV3ZXIgcGVyc29uYWwgZm91bHMgc2lnbmlmaWNhbnRseSBpbXBhY3Qgd2lubmluZy4NCioqKioqDQoNCiMjIyMgU3VwcG9ydGluZyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCmdhbWUyX2ZpbHRlcmVkIDwtIGZpbHRlcihnYW1lMiwgWWVhciAhPSAyMDIwKQ0KDQpwMiA8LSBnZ3Bsb3QoZ2FtZTJfZmlsdGVyZWQsIGFlcyh4ID0gREVTLCB5ID0gUEYgLCBjb2xvciA9IE91dGNvbWUsIHRleHQgPVRlYW1SYW5rKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHggPSAiRGVmZW5zaXZlIEVmZmljaWVuY3kgU2NvcmUiLCB5ID0gIlBlcnNvbmFsIEZvdWxzIENvbW1pdGVkIiwgY29sb3IgPSAiR2FtZSBPdXRjb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKC4gfiBZZWFyKSArDQogIGdndGl0bGUoIkVmZmljaWVuY3kgb2YgRGVmZW5zaXZlIFBvc3Nlc3Npb25zIikgKw0KICB0aGVtZShwYW5lbC5zcGFjaW5nLnggPSB1bml0KDUsICJtbSIpKQ0KDQpnZ3Bsb3RseShwMiwgdG9vbHRpcCA9IGMoInRleHQiKSwgd2lkdGggPSA5MDAsIGhlaWdodCA9IDMwMCkNCg0KYGBgDQoqKioqKg0KDQojIyMjIEluIHRoZSBncmFwaHMgYWJvdmUsIHdlIGNhbiBzZWUgYSBtb2RlcmF0ZSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG91ciB2YXJpYWJsZXMuIFRoaXMgcmVzdWx0IGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgY29ycmVsYXRpb24gd2UgZm91bmQgZWFybGllciAoLTAuMjc3KS4gVGhpcyByZWxhdGlvbnNoaXAgc3VnZ2VzdHMgdGhhdCBwZXJzb25hbCBmb3VscyBkZWNyZWFzZSBhcyBERVMgaW5jcmVhc2VzLiBDb21iaW5pbmcgY29ycmVsYXRpb24gYW5kIGRpZmZlcmVuY2Ugb2YgbWVhbnMgd2UgY2FuIGFkdmlzZSB0aGUgQnVjaydzIGNvYWNoaW5nIHN0YWZmIHRvIGVtcGhhc2l6ZSBzdHJhdGVnaWMgcG9zaXRpb25pbmcgYW5kIHRlYW0gZGVmZW5zZSB0byB3aW4gdGhlIG1vc3QgZ2FtZXMuDQoNCioqKioqDQojIyMjIEVmZmVjdCBvZiBUaGVlIFBvaW50IEZpZWxkIEdvYWwgQXR0ZW1wdHMgb24gT3V0Y29tZXMgKFNob290aW5nKQ0KYGBge3J9DQpnYW1lMyA8LSBnYW1lcyAlPiUNCiAgZ3JvdXBfYnkoT3V0Y29tZSwgWWVhciwgUmFuaykgJT4lDQogIHN1bW1hcmlzZShUZWFtUmFuayA9IHBhc3RlKFRlYW0sICJSYW5rIC0iLCBSYW5rLCBzZXAgPSAiICIpLCBgM1BBYCA9IGAzUEFgLCBgM1AlYCA9IGAzUCVgLCBQZXJjZW50X2F0dGVtcHQgPSAoYDNQJWAvYDNQQWApKQ0KDQpnYW1lXzMgPC0gZ2FtZTMgJT4lDQogIG11dGF0ZShPdXRjb21lID0gaWZlbHNlKE91dGNvbWUgPT0gIlciLCAxLDApKQ0KDQojIE51bGwgSHlwb3RoZXNpczogVGhlIHZhbHVlIG9mIHRoZSBQZXJjZW50LUF0dGVtcHQgcmF0aW8gaGFzIG1pbmltYWwgaW1wYWN0IGdhbWUgb3V0Y29tZQ0KDQpzaG90X2NvcnIgPC0gY29yKGdhbWVfMyRQZXJjZW50X2F0dGVtcHQsZ2FtZV8zJGAzUEFgLCBtZXRob2QgPSAicGVhcnNvbiIpICANCnNob3RfbW9kZWwgPC0gd2lsY294LnRlc3QoZ2FtZTMkUGVyY2VudF9hdHRlbXB0IH4gZ2FtZTMkT3V0Y29tZSwgY29uZi5pbnQgPVQpDQoNCiMgTWVhbiBvZiBQZXJjZW50LUF0dGVtcHQgcmF0aW8gZm9yIFdpbnMNCnNob3Rfd2lucyA8LSBnYW1lMyAlPiUNCiAgc2VsZWN0KE91dGNvbWUsIFllYXIsIFJhbmssIFBlcmNlbnRfYXR0ZW1wdCkgJT4lDQogIGZpbHRlcihPdXRjb21lID09ICJXIikNCnNob3RXX21lYW4gPC0gbWVhbihzaG90X3dpbnMkUGVyY2VudF9hdHRlbXB0KSANCiAgDQojIE1lYW4gb2YgUGVyY2VudC1BdHRlbXB0IHJhdGlvIGZvciBMb3NzZXMNCnNob3RfbG9zc2VzIDwtIGdhbWUzICU+JQ0KICBzZWxlY3QoT3V0Y29tZSwgWWVhciwgUmFuaywgUGVyY2VudF9hdHRlbXB0KSAlPiUNCiAgZmlsdGVyKE91dGNvbWUgPT0gIkwiKQ0Kc2hvdExfbWVhbiA8LSBtZWFuKHNob3RfbG9zc2VzJFBlcmNlbnRfYXR0ZW1wdCkNCg0KcHJpbnQoc2hvdF9jb3JyKSAjIENvcnJlbGF0aW9uDQpwcmludChzaG90X21vZGVsKSAjIFUgVGVzdA0KcHJpbnQoc2hvdFdfbWVhbikgIyBNZWFuIG9mIFBlcmNlbnQtQXR0ZW1wdCByYXRpbyBmb3IgV2lucw0KcHJpbnQoc2hvdExfbWVhbikgIyBNZWFuIG9mIFBlcmNlbnQtQXR0ZW1wdCByYXRpbyBmb3IgTG9zc2VzDQpgYGANCioqKioqDQoNCiMjIyMgTGV0J3MgZGVmaW5lIHRoZSB2YXJpYWJsZXMgd2UgZm9jdXNlZCBvbiBhYm92ZTogQSB0aHJlZS1wb2ludCBhdHRlbXB0IGlzIGEgc2hvdCByZWxlYXNlZCBmcm9tIGFueSBwb3NpdGlvbiBiZWhpbmQgdGhlIHRocmVlLXBvaW50IGFyYy4gVGhlIHBlcmNlbnQtYXR0ZW1wdCByYXRpbyB0YWtlcyBib3RoIHNob290aW5nIGFjY3VyYWN5IGFuZCB0aGUgdm9sdW1lIGludG8gYWNjb3VudCB0byBtZWFzdXJlIHNob290aW5nIGVmZmljZW5jeS4NCg0KIyMjIyBIZXJlLCB3ZSBleHBsb3JlZCB0aGUgcGVyY2VudC1hdHRlbXB0IHJhdGlvJ3MgaW1wYWN0IG9uIHRoZSBnYW1lIG91dGNvbWUgYWJvdmUuIFRoZSBNYW5uLVdoaXRuZXkgVSB0ZXN0cywgb25jZSBhZ2Fpbiwgc2hvdyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gbWVhbnMgYmV0d2VlbiBnYW1lcyB3b24gYW5kIGxvc3QgKFAtVmFsdWUgOiAwLjAwMDMpLiBJZiB3ZSBmdXJ0aGVyIGludGVycHJldCB0aGUgY2FsY3VsYXRlZCBtZWFucywgd2Ugc2VlIHRoYXQgZmV3ZXIgcGVyc29uYWwgZm91bHMgc2lnbmlmaWNhbnRseSBpbXBhY3Qgd2lubmluZy4NCg0KKioqKioNCiMjIyMgU3VwcG9ydGluZyBWaXN1YWxpemF0aW9uDQpgYGB7cn0NCmdhbWUzX2ZpbHRlcmVkIDwtIGZpbHRlcihnYW1lMywgWWVhciAhPSAyMDIwKQ0KDQpwMyA8LSBnZ3Bsb3QoZ2FtZTNfZmlsdGVyZWQsIGFlcyh4ID0gUGVyY2VudF9hdHRlbXB0LCB5ID0gYDNQQWAgLCBjb2xvciA9IE91dGNvbWUsIHRleHQgPVRlYW1SYW5rKSkgKw0KICBnZW9tX3BvaW50KCkrDQogIGxhYnMoeCA9ICJTaG9vdGluZyBBY2N1cmFjeSBTY29yZSIsIHkgPSAiMyBQb2ludCBGaWVsZCBHb2FsIEF0dGVtcHRzIiwgY29sb3IgPSAiR2FtZSBPdXRjb21lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBmYWNldF93cmFwKC4gfiBZZWFyKSArDQogIGdndGl0bGUoIkltcGFjdCBvZiAzIFBvaW50IEZpZWxkIEdvYWwgQXR0ZW1wdHMiKSArDQogIHRoZW1lKHBhbmVsLnNwYWNpbmcueCA9IHVuaXQoNSwgIm1tIikpDQoNCmdncGxvdGx5KHAzLCB0b29sdGlwID0gYygidGV4dCIpLCB3aWR0aCA9IDkwMCwgaGVpZ2h0ID0gMzAwKQ0KYGBgDQoqKioqKg0KIyMjIyBGaW5hbGx5LCB3ZSBjYW4gc2VlIHRoZSBzdHJvbmdlc3QgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBvdXIgdmFyaWFibGVzICgtMC41OTIpLiBUaGlzIHJlbGF0aW9uc2hpcCBzdWdnZXN0cyB0aGF0IGFzIHRocmVlLXBvaW50IGF0dGVtcHRzIGRlY3JlYXNlLCB0aGUgcGVyY2VudC1hdHRlbXB0IHJhdGlvIGluY3JlYXNlcy4gQ29tYmluaW5nIGNvcnJlbGF0aW9uIGFuZCB0aGUgVSB0ZXN0IHdlIGNhbiBhZHZpc2UgQnVjaydzIGNvYWNoaW5nIHN0YWZmIHRvIHN0cmF0ZWdpemUgYW5kIGNyZWF0ZSBvcGVuIHNob290cyBpbnN0ZWFkIG9mIGZyZXF1ZW50IG9uZXMuDQoNCioqKioqDQojIyMgQ29uY2x1c2lvbg0KDQojIyMjIEFmdGVyIGV4YW1pbmluZyB0aGUgdGhyZWUgbW9zdCBpbXBhY3RmdWwgZWxlbWVudHMgKE9mZmVuc2UsIERlZmVuc2UsIGFuZCBTaG9vdGluZyksIHdlIHByb3ZpZGVkIHRoZSBNaWx3YXVrZWUgQnVja3MgY29hY2hpbmcgc3RhZmYgd2l0aCBtZWFuaW5nZnVsIGluc2lnaHRzIGJhY2tlZCBieSByZWxpYWJsZSBzdGF0aXN0aWNhbCB0ZXN0cy4gTm93LCBpdCBpcyB1cCB0byB0aGVpciBvcmdhbml6YXRpb24gdG8gaW1wbGVtZW50IHRoZW0gYXBwcm9wcmlhdGVseSBhcyB0aGV5IGVudGVyIHRoZSBwbGF5b2Zmcy4NCg0KKioqKio=